home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / UUPC11QS.ARJ / COMM.ASM < prev    next >
Assembly Source File  |  1991-12-08  |  32KB  |  1,209 lines

  1.     TITLE    COM_PKG2 -- Last updated 10/6/85
  2.     PAGE    75,132
  3. ;
  4. ; Modified to use COM1 thru COM4 - William W. Plummer, 2/21/91
  5. ; Eliminate (incomplete) support for DOS1 - William W. Plummer, 11/13/90
  6. ;
  7. ;    modified to use MSC calling sequence.
  8. ;    jrr 3/86
  9. ;
  10. ; Communications Package for the IBM PC, XT, AT and PCjr
  11. ; and strict compatibles.
  12. ; May be copied and used freely -- This is a public domain program
  13. ; Developed by Richard Gillmann, John Romkey, Jerry Saltzer,
  14. ; Craig Milo Rogers, Dave Mitton and Larry Afrin.
  15. ;
  16. ; We'd sure like to see any improvements you might make.
  17. ; Please send all comments and queries about this package
  18. ; to GILLMANN@USC-ISIB.ARPA
  19. ;
  20. ; o Supports both serial ports simultaneously
  21. ; o All speeds to 19200 baud
  22. ; o Compatible with PC, XT, AT and PCjr.
  23. ; o Built in XON/XOFF flow control option
  24. ; o Assembly language calling conventions
  25. ; o Logs all comm errors
  26. ; o Direct connect or modem protocol
  27. ;
  28. ; MAXIMUM BUFFER SIZES
  29. R_SIZE    EQU    2048        ; SIZE OF RECEIVE BUFFERS skl/88-05-13
  30. S_SIZE    EQU    500        ; SIZE OF TRANSMIT BUFFERS rhl/4/86
  31. ; INTERRUPT NUMBERS
  32. INT_COM1 EQU    0CH        ; COM1: FROM 8259
  33. INT_COM2 EQU    0BH        ; COM2: FROM 8259
  34. INT_COM3 EQU    0CH        ; COM3: FROM 8259
  35. INT_COM4 EQU    0BH        ; COM4: FROM 8259
  36. ; 8259 PORTS
  37. INTA00    EQU    20H        ; 8259A PORT, A0 = 0
  38. INTA01    EQU    21H        ; 8259A PORT, A0 = 1
  39. ; COM1: & COM3: LEVEL 4
  40. IRQ4    EQU    2*2*2*2         ; 8259A OCW1 MASK, M4=1, A0=0
  41. NIRQ4    EQU    NOT IRQ4 AND 0FFH    ; COMPLEMENT OF ABOVE
  42. EOI4    EQU    4 OR 01100000B        ; 8259A OCW2 SPECIFIC IRQ4 EOI, A0=0
  43. ; COM2: & COM4: LEVEL 3
  44. IRQ3    EQU    2*2*2            ; 8259A OCW1 MASK, M3=1, A0=0
  45. NIRQ3    EQU    NOT IRQ3 AND 0FFH    ; COMPLEMENT OF ABOVE
  46. EOI3    EQU    3 OR 01100000B        ; 8259A OCW2 SPECIFIC IRQ3 EOI, A0=0
  47.  
  48. ; FLOW CONTROL CHARACTERS
  49. CONTROL_Q EQU    11H        ; XON
  50. CONTROL_S EQU    13H        ; XOFF
  51. ; MISC.
  52. DOS    EQU    21H        ; DOS FUNCTION CALLS
  53.     PAGE
  54. ;
  55. ; ROM BIOS Data Area
  56. ;
  57. RBDA    SEGMENT AT 40H
  58. RS232_BASE DW    4 DUP(?)    ; ADDRESSES OF RS232 ADAPTERS
  59. RBDA    ENDS
  60. ;
  61. ; ROM PC-Type IDENT
  62. ;
  63. ROM    SEGMENT AT 0F000H
  64.     ORG    0FFFEH
  65. ROMID    DB    ?        ; 0FFH=PC OR EARLY XT, 0FEH=XT, 0FDH=JR
  66. ROM    ENDS
  67.     PAGE
  68. ;
  69. ; TABLE FOR EACH SERIAL PORT
  70. ;
  71. SP_TAB        STRUC
  72. PORT        DB    ?    ; 1 OR 2 OR 3 OR 4
  73. ; PARAMETERS FOR THIS INTERRUPT LEVEL
  74. INT_COM     DB    ?    ; INTERRUPT NUMBER
  75. IRQ        DB    ?    ; 8259A OCW1 MASK
  76. NIRQ        DB    ?    ; COMPLEMENT OF ABOVE
  77. EOI        DB    ?    ; 8259A OCW2 SPECIFIC END OF INTERRUPT
  78. ; INTERRUPT HANDLERS FOR THIS LEVEL
  79. INT_HNDLR    DW    ?    ; OFFSET TO INTERRUPT HANDLER
  80. OLD_COM_OFF    DW    ?    ; OLD HANDLER'S OFFSET
  81. OLD_COM_SEG    DW    ?    ; OLD HANDLER'S SEGMENT
  82. ; ATTRIBUTES
  83. INSTALLED    DB    ?    ; IS PORT INSTALLED ON THIS PC? (1=YES,0=NO)
  84. BAUD_RATE    DW    ?    ; 19200 MAX
  85. CONNECTION    DB    ?    ; M(ODEM), D(IRECT)
  86. PARITY        DB    ?    ; N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
  87. STOP_BITS    DB    ?    ; 1, 2
  88. XON_XOFF    DB    ?    ; E(NABLED), D(ISABLED)
  89. ; FLOW CONTROL STATE
  90. HOST_OFF    DB    ?    ; HOST XOFF'ED (1=YES,0=NO)
  91. PC_OFF        DB    ?    ; PC XOFF'ED (1=YES,0=NO)
  92. ; ERROR COUNTS
  93. ERROR_BLOCK    DW    8 DUP(?)    ; EIGHT ERROR COUNTERS
  94. ; 8250 PORTS
  95. DATREG        DW    ?    ; DATA REGISTER
  96. IER        DW    ?    ; INTERRUPT ENABLE REGISTER
  97. IIR        DW    ?    ; INTERRUPT IDENTIFICATION REGISTER
  98. LCR        DW    ?    ; LINE CONTROL REGISTER
  99. MCR        DW    ?    ; MODEM CONTROL REGISTER
  100. LSR        DW    ?    ; LINE STATUS REGISTER
  101. MSR        DW    ?    ; MODEM STATUS REGISTER
  102. ; BUFFER POINTERS
  103. START_TDATA    DW    ?    ; INDEX TO FIRST CHARACTER IN X-MIT BUFFER
  104. END_TDATA    DW    ?    ; INDEX TO FIRST FREE SPACE IN X-MIT BUFFER
  105. START_RDATA    DW    ?    ; INDEX TO FIRST CHARACTER IN REC. BUFFER
  106. END_RDATA    DW    ?    ; INDEX TO FIRST FREE SPACE IN REC. BUFFER
  107. ; BUFFER COUNTS
  108. SIZE_TDATA    DW    ?    ; NUMBER OF CHARACTERS IN X-MIT BUFFER
  109. SIZE_RDATA    DW    ?    ; NUMBER OF CHARACTERS IN REC. BUFFER
  110. ; BUFFERS
  111. TDATA        DB    S_SIZE DUP(?)    ; SEND BUFFER
  112. RDATA        DB    R_SIZE DUP(?)    ; RECEIVE BUFFER
  113. SP_TAB        ENDS
  114. ; SP_TAB EQUATES
  115. ; WE HAVE TO USE THESE BECAUSE OF PROBLEMS WITH STRUC
  116. EOVFLOW     EQU    ERROR_BLOCK    ; BUFFER OVERFLOWS
  117. EOVRUN        EQU    ERROR_BLOCK+2    ; RECEIVE OVERRUNS
  118. EBREAK        EQU    ERROR_BLOCK+4    ; BREAK CHARS
  119. EFRAME        EQU    ERROR_BLOCK+6    ; FRAMING ERRORS
  120. EPARITY     EQU    ERROR_BLOCK+8    ; PARITY ERRORS
  121. EXMIT        EQU    ERROR_BLOCK+10    ; TRANSMISSION ERRORS
  122. EDSR        EQU    ERROR_BLOCK+12    ; DATA SET READY ERRORS
  123. ECTS        EQU    ERROR_BLOCK+14    ; CLEAR TO SEND ERRORS
  124. DLL        EQU    DATREG        ; LOW DIVISOR LATCH
  125. DLH        EQU    IER        ; HIGH DIVISOR LATCH
  126.     PAGE
  127. ;    put the data in the DGROUP segment
  128. ;    far calls enter with DS pointing to DGROUP
  129. ;
  130. DGROUP    GROUP _DATA
  131. _DATA    SEGMENT PUBLIC 'DATA'
  132. ;
  133. DIV50PC     EQU    2304        ; DIVISOR FOR 50 BAUD (PC,XT)
  134. DIV50JR     EQU    2237        ; DIVISOR FOR 50 BAUD (JR)
  135. DIV50        DW    2304        ; ACTUAL DIVISOR FOR 50 BAUD IN USE
  136. CURRENT_AREA    DW    AREA1        ; CURRENTLY SELECTED AREA
  137. ; DATA AREAS FOR EACH PORT
  138. AREA1    SP_TAB    <1,INT_COM1,IRQ4,NIRQ4,EOI4>    ; COM1 DATA AREA
  139. AREA2    SP_TAB    <2,INT_COM2,IRQ3,NIRQ3,EOI3>    ; COM2 DATA AREA
  140. AREA3    SP_TAB    <3,INT_COM3,IRQ4,NIRQ4,EOI4>    ; COM3 DATA AREA
  141. AREA4    SP_TAB    <4,INT_COM4,IRQ3,NIRQ3,EOI3>    ; COM4 DATA AREA
  142. _DATA     ENDS
  143.     PAGE
  144. COM_TEXT    SEGMENT PARA PUBLIC 'CODE'
  145.     ASSUME    CS:COM_TEXT,DS:DGROUP,ES:NOTHING
  146.  
  147.     PUBLIC    _select_port
  148.     PUBLIC    _save_com
  149.     PUBLIC    _install_com
  150.     PUBLIC    _restore_com
  151.     PUBLIC    _open_com
  152.     PUBLIC    _close_com
  153.     PUBLIC    _dtr_on
  154.     PUBLIC    _dtr_off
  155.     PUBLIC    _r_count
  156.     PUBLIC    _s_count
  157.     PUBLIC    _receive_com
  158.     PUBLIC    _send_com
  159.     PUBLIC    _sendi_com
  160.     PUBLIC    _send_local
  161.     PUBLIC    _break_com
  162.     PUBLIC    _com_errors
  163.     PUBLIC    _modem_status
  164.     PAGE
  165.  
  166.  
  167. ; Here's the order of calls in UUPC.  The routines in COMM.ASM are called
  168. ; from ulib.c.
  169.  
  170. ; First (when a line in system has been read?), ulib&openline calls
  171. ;        select_port()        ; Sets up CURRENT_AREA
  172. ; then,     save_com()        ; Save INT vector
  173. ; then,     install_com()        ; Init area, hook INT
  174. ; then,     open_com(&cmd, 'D', 'N', STOP*T, 'D') ; Init UART, clr bufs
  175. ; then,     dtr_on().
  176.  
  177. ; At that point the line is up and running.  UUPC calls ulib&sread()
  178. ; which calls,    receive_com();
  179.  
  180. ; And UUPC calls ulib&swrite()
  181. ; which calls,    send_com();
  182.  
  183. ; To cause an error that the receiver will see, UUPC calls ulib&ssendbrk();
  184. ; which calls,    break_com();
  185.  
  186. ; When all done with the line, UUPC calls ulib&closeline()
  187. ; which calls,    dtr_off();
  188. ; then,     close_com();
  189. ; then,     restore_com();        ; Unhook INT
  190. ; and,        stat_errors();
  191.  
  192.  
  193. ; Note that on the PC COM1 and COM3 share IRQ4, while COM2 and COM4 share IRQ3.
  194. ; BUT, only one device on a given IRQ line can be active at a time.  So it is
  195. ; sufficient for UUPC to hook whatever IRQ INT its modem is on as long as it
  196. ; unhooks it when it is done with that COM port.  COMM cannot be an installed
  197. ; device driver since it must go away when UUPC is done so that other devices
  198. ; on the same INTs will come back to life.  Also, it is OK to have a static
  199. ; CURRENT_AREA containing the current area that UUPC is using.
  200.  
  201.     PAGE
  202. ;
  203. ; SELECT WHICH PORT IS TO BE "ACTIVE"
  204. ;    [bp+6] = port number
  205. _select_port    PROC FAR
  206.     push bp
  207.     mov bp,sp
  208.     mov AX,[bp+6]    ; get aguement
  209.     CMP    AL,1        ; Port 1?
  210.      JE    SP1        ; Yes
  211.     CMP    AL,2        ; Port 2?
  212.      JE    SP2        ; Yes
  213.     CMP    AL,3        ; Port 3?
  214.      JE    SP3        ; Yes
  215.     CMP    AL,4        ; Port 4?
  216.      JE    SP4        ; Yes
  217.     INT 20H         ; N.O.T.A. ????? Halt for debugging!
  218.     ; Assume port 1 if continued
  219. SP1:    MOV    AX,OFFSET DGROUP:AREA1    ; SELECT COM1 DATA AREA
  220.     JMP    SHORT SPX    ; CONTINUE
  221. SP2:    MOV    AX,OFFSET DGROUP:AREA2    ; SELECT COM2 DATA AREA
  222.     JMP    SHORT SPX    ; CONTINUE
  223. SP3:    MOV    AX,OFFSET DGROUP:AREA3    ; SELECT COM3 DATA AREA
  224.     JMP    SHORT SPX    ; CONTINUE
  225. SP4:    MOV    AX,OFFSET DGROUP:AREA4    ; SELECT COM4 DATA AREA
  226.     ;Fall into SPX
  227. SPX:    MOV    CURRENT_AREA,AX ; SET SELECTION IN MEMORY
  228.     mov sp,bp
  229.     pop bp
  230.     RET            ; DONE
  231. _select_port    ENDP
  232.     PAGE
  233. ;
  234. ; SAVE ORIGINAL COM VECTOR
  235. ;
  236. _save_com    PROC FAR
  237.     push bp
  238.     mov bp,sp
  239.     push si
  240.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  241.     PUSH    ES        ; SAVE EXTRA SEGMENT
  242.     MOV    AREA1.INT_HNDLR,OFFSET INT_HNDLR1
  243.     MOV    AREA2.INT_HNDLR,OFFSET INT_HNDLR2
  244.     MOV    AREA3.INT_HNDLR,OFFSET INT_HNDLR3
  245.     MOV    AREA4.INT_HNDLR,OFFSET INT_HNDLR4
  246.  
  247. ; Save old interrupt vector
  248.     MOV    AH,35H        ; FETCH INTERRUPT VECTOR CONTENTS
  249.     MOV    AL,INT_COM[SI]    ; INTERRUPT NUMBER
  250.     INT    DOS        ; DOS 2 FUNCTION
  251.     MOV    OLD_COM_OFF[SI],BX    ; SAVE
  252.     MOV    BX,ES            ; ES:BX
  253.     MOV    OLD_COM_SEG[SI],BX    ; FOR LATER RESTORATION
  254.     POP    ES        ; RESTORE ES
  255.     pop si
  256.     mov sp,bp
  257.     pop bp
  258.     RET            ; DONE
  259. _save_com    ENDP
  260.     PAGE
  261. ;
  262. ; INSTALL_COM:    INSTALL THE ACTIVE PORT
  263. ;
  264. ; SET 8250 PORTS FROM RS-232 BASE IN ROM BIOS DATA AREA
  265. ; INITIALIZE PORT CONSTANTS AND ERROR COUNTS
  266. ; INSTALL INTERRUPT VECTOR
  267. ;
  268. ;    return ax=1 on success ax=0 on failure
  269. ;
  270. _install_com    PROC FAR
  271.     push bp
  272.     mov bp,sp
  273.     push si
  274.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  275.     PUSH    ES        ; SAVE EXTRA SEGMENT
  276.     CMP    INSTALLED[SI],1 ; Is port installed on this machine?
  277.      JNE    INSTOK        ; NO, CONTINUE
  278.     JMP    INSTX        ; ELSE JUMP IF ALREADY INSTALLED
  279. ; CLEAR ERROR COUNTS
  280. INSTOK: MOV    WORD PTR EOVFLOW[SI],0    ; BUFFER OVERFLOWS
  281.     MOV    WORD PTR EOVRUN[SI],0    ; RECEIVE OVERRUNS
  282.     MOV    WORD PTR EBREAK[SI],0    ; BREAK CHARS
  283.     MOV    WORD PTR EFRAME[SI],0    ; FRAMING ERRORS
  284.     MOV    WORD PTR EPARITY[SI],0    ; PARITY ERRORS
  285.     MOV    WORD PTR EXMIT[SI],0    ; TRANSMISSION ERRORS
  286.     MOV    WORD PTR EDSR[SI],0    ; DATA SET READY ERRORS
  287.     MOV    WORD PTR ECTS[SI],0    ; CLEAR TO SEND ERRORS
  288. ; SENSE PC TYPE AND SET DIVISOR ACCORDINGLY
  289.     MOV    BX,ROM        ; HIGH ROM SEGMENT
  290.     MOV    ES,BX        ; TO ES
  291.     ASSUME    ES:ROM
  292.     MOV    DIV50,DIV50PC    ; ASSUME PC OR XT
  293.     CMP    ROMID,0FDH    ; IS IT A PCjr?
  294.      JNE    INST0        ; JUMP IF NOT
  295.     MOV    DIV50,DIV50JR    ; ELSE SET JR DIVISOR
  296. ; SET 8250 PORT ADDRESSES
  297. INST0:    MOV    BX,RBDA     ; ROM BIOS DATA AREA
  298.     MOV    ES,BX        ; TO ES
  299.     ASSUME    ES:RBDA
  300.     CMP    PORT[SI],1    ; PORT 1?
  301.      JE    INST3F8     ; Yes
  302.     CMP    PORT[SI],2    ; PORT 2?
  303.      JE    INST2F8     ; Yes
  304.     CMP    PORT[SI],3    ; PORT 3?
  305.      JE    INST3E8     ; Yes
  306.     CMP    PORT[SI],4    ; PORT 4?
  307.      JE    INST2E8     ; Yes
  308.     INT    20H        ; N.O.T.A. (Caller is screwed up badly!)
  309.  
  310. INST3F8:MOV    AX,3F8H     ; COM1 BASE PORT ADDRESS
  311.     JMP    SHORT INST2    ; CONTINUE
  312.  
  313. INST2F8:MOV    AX,2F8H     ; COM2 BASE PORT ADDRESS
  314.     JMP    SHORT INST2    ; CONTINUE
  315.  
  316. INST3E8:
  317.     CMP    RS232_BASE+4,0000H     ; We have information?
  318.     JE    INST3E8_A           ; No --> Use default
  319.     MOV    AX,RS232_BASE+4        ; Yes --> Use provided info
  320.     JMP    SHORT INST2    ; CONTINUE
  321.  
  322. INST3E8_A:
  323.     MOV    AX,3E8H     ; COM3 BASE PORT ADDRESS
  324.     JMP    SHORT INST2    ; CONTINUE
  325.  
  326. INST2E8:
  327.     CMP    RS232_BASE+6,0000H     ; We have information?
  328.     JE    INST2E8_A           ; No --> Use default
  329.     MOV    AX,RS232_BASE+6        ; Yes --> Use provided info
  330.     JMP    SHORT INST2    ; CONTINUE
  331.  
  332. INST2E8_A:
  333.     MOV    AX,2E8H     ; COM4 BASE PORT ADDRESS
  334.     ; Fall into INST2
  335.  
  336. INST2:    CMP    AX,RS232_BASE    ; INSTALLED?
  337.      JE    INST2A        ; JUMP IF SO
  338.     CMP    AX,RS232_BASE+2 ; INSTALLED?
  339.      JE    INST2A        ; JUMP IF SO
  340.     CMP    AX,RS232_BASE+4 ; INSTALLED?
  341.      JE    INST2A        ; JUMP IF SO
  342.     CMP    AX,RS232_BASE+6 ; INSTALLED?
  343.      JNE    INST666     ; JUMP IF NOT
  344.     ; Fall into INST2A
  345.  
  346. INST2A: MOV    BX,DATREG    ; OFFSET OF TABLE OF PORTS
  347.     MOV    CX,7        ; LOOP SIX TIMES
  348. INST3:    MOV    WORD PTR [SI][BX],AX ; SET PORT ADDRESS
  349.     INC    AX        ; NEXT PORT
  350.     ADD    BX,2        ; NEXT WORD ADDRESS
  351.     LOOP    INST3        ; RS232 BASE LOOP
  352. ; RESET VECTOR TO POINT TO OUR HANDLER
  353.     MOV    AREA1.INT_HNDLR,OFFSET INT_HNDLR1   ;;;Aready done in SaveCom
  354.     MOV    AREA2.INT_HNDLR,OFFSET INT_HNDLR2
  355.     MOV    AREA3.INT_HNDLR,OFFSET INT_HNDLR3
  356.     MOV    AREA4.INT_HNDLR,OFFSET INT_HNDLR4
  357.     MOV    AH,25H        ; SET INTERRUPT VECTOR CONTENTS
  358.     MOV    AL,INT_COM[SI]    ; INTERRUPT NUMBER
  359.     MOV    DX,OFFSET DGROUP:INT_HNDLR[SI] ; OUR INTERRUPT HANDLER
  360.     PUSH    DS        ; SAVE DATA SEGMENT
  361.     PUSH    CS        ; COPY CS
  362.     POP    DS        ; TO DS
  363.     INT    DOS        ; DOS FUNCTION
  364.     POP    DS        ; RECOVER DATA SEGMENT
  365. ; PORT INSTALLED
  366. INSTX:    MOV    INSTALLED[SI],1 ; PORT INSTALLED
  367.     POP    ES        ; RESTORE ES
  368.     mov ax,1
  369.     pop si
  370.     mov sp,bp
  371.     pop bp
  372.     RET            ; DONE
  373.  
  374. ; PORT NOT INSTALLED
  375. INST666:MOV    INSTALLED[SI],0 ; PORT NOT INSTALLED ON THIS PC
  376.     POP    ES        ; RESTORE ES
  377.     mov ax,0
  378.     pop si
  379.     mov sp,bp
  380.     pop bp
  381.     RET            ; DONE
  382. _install_com    ENDP
  383.     PAGE
  384. ;
  385. ; RESTORE ORIGINAL INTERRUPT VECTOR
  386. ;
  387. _restore_com    PROC FAR
  388.     push bp
  389.     mov bp,sp
  390.     push si
  391.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  392.     MOV    INSTALLED[SI],0 ; PORT IS NO LONGER INSTALLED
  393.     MOV    AH,25H        ; SET INTERRUPT VECTOR FUNCTION
  394.     MOV    AL,INT_COM[SI]    ; INTERRUPT NUMBER
  395.     MOV    DX,OLD_COM_OFF[SI] ; OLD OFFSET TO DX
  396.     MOV    BX,OLD_COM_SEG[SI] ; OLD SEG
  397.     PUSH    DS        ; SAVE DS
  398.     MOV    DS,BX        ; TO DS
  399.     INT    DOS        ; DOS FUNCTION
  400.     POP    DS        ; RECOVER DS
  401.     pop si
  402.     mov sp,bp
  403.     pop bp
  404.     RET            ; DONE
  405. _restore_com    ENDP
  406.     PAGE
  407. ;
  408. ; OPEN_COM ON CURRENT PORT
  409. ;
  410. ; CLEAR BUFFERS
  411. ; RE-INITIALIZE THE INTEL 8250 UART
  412. ; ENABLE INTERRUPTS ON THE INTEL 8259 INTERRUPT CONTROL CHIP
  413. ;
  414. ; [bp+6] = BAUD RATE
  415. ; [bp+8] = CONNECTION: M(ODEM), D(IRECT)
  416. ; [bp+10] = PARITY:    N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
  417. ; [bp+12] = STOP BITS:    1, 2
  418. ; [bp+14] = XON/XOFF:    E(NABLED), D(ISABLED)
  419. ;
  420. _open_com    PROC FAR
  421.     push bp
  422.     mov bp,sp
  423.     push si
  424.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  425.  
  426.     CLI                ; INTERRUPTS OFF
  427.     mov ax,[bp+6]
  428.     MOV    BAUD_RATE[SI],AX    ; SET
  429.     mov bh,[bp+8]
  430.     MOV    CONNECTION[SI],BH    ;     ARGS
  431.     mov bl,[bp+10]
  432.     MOV    PARITY[SI],BL        ;       IN
  433.     mov ch,[bp+12]
  434.     MOV    STOP_BITS[SI],CH    ;          MEMORY
  435.     mov cl,[bp+14]
  436.     MOV    XON_XOFF[SI],CL
  437.  
  438. ; RESET FLOW CONTROL
  439.     MOV    HOST_OFF[SI],0        ; HOST FLOWING
  440.     MOV    PC_OFF[SI],0        ; PC FLOWING
  441.  
  442. ; RESET BUFFER COUNTS AND POINTERS
  443.     MOV    START_TDATA[SI],0
  444.     MOV    END_TDATA[SI],0
  445.     MOV    START_RDATA[SI],0
  446.     MOV    END_RDATA[SI],0
  447.     MOV    SIZE_TDATA[SI],0
  448.     MOV    SIZE_RDATA[SI],0
  449.  
  450.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  451.     JNZ    OC1            ; SKIP IF SO
  452.     JMP    OCX            ; ELSE ABORT
  453. OC1:
  454. ; RESET THE 8250
  455.     MOV    AL,0
  456.     MOV    DX,MCR[SI]
  457.     OUT    DX,AL
  458.     JMP    $+2        ; I/O DELAY FOR JR
  459.  
  460.     MOV    DX,LSR[SI]    ; RESET LINE STATUS CONDITION
  461.     IN    AL,DX
  462.     JMP    $+2        ; I/O DELAY FOR JR
  463.     MOV    DX,DATREG[SI]    ; RESET RECSIVE DATA CONDITION
  464.     IN    AL,DX
  465.     JMP    $+2        ; I/O DELAY FOR JR
  466.     MOV    DX,MSR[SI]    ; RESET MODEM DELTAS AND CONDITIONS
  467.     IN    AL,DX
  468.  
  469. ; CONVERT PASSED BAUD RATE TO 8250 DIVISOR
  470.     MOV    AX,50        ; 50 BAUD
  471.     MUL    DIV50        ; TIMES ITS DIVISOR
  472.     DIV    BAUD_RATE[SI]    ; OTHER SPEEDS ARE PROPORTIONAL
  473.     MOV    BX,AX        ; RESULT TO BX
  474.  
  475. ; SET 8250 DIVISOR
  476.     MOV    DX,LCR[SI]    ; LINE CONTROL REGISTER
  477.     MOV    AL,80H        ; HI BIT ON
  478.     OUT    DX,AL        ; SET DLAB = 1
  479.     JMP    $+2        ; I/O DELAY FOR JR
  480.     MOV    DX,WORD PTR DLL[SI]    ; LEAST SIGNIFICANT BYTE
  481.     MOV    AL,BL        ; LSB FROM TABLE
  482.     OUT    DX,AL        ; SET LSB ON 8250
  483.     JMP    $+2        ; I/O DELAY FOR JR
  484.     MOV    DX,WORD PTR DLH[SI]    ; MOST SIGNIFICANT BYTE
  485.     MOV    AL,BH        ; MSB FROM TABLE
  486.     OUT    DX,AL        ; SET MSB ON 8250
  487.     JMP    $+2        ; I/O DELAY FOR JR
  488.  
  489. ; SET PARITY AND NUMBER OF STOP BITS
  490.     MOV    AL,03H        ; NONE OR SPACE PARITY IS THE DEFAULT
  491.     CMP    PARITY[SI],'O'  ; ODD PARITY REQUESTED?
  492.     JNE    P1        ; JUMP IF NOT
  493.     MOV    AL,0AH        ; SELECT ODD PARITY
  494.     JMP    SHORT P3    ; CONTINUE
  495. P1:    CMP    PARITY[SI],'E'  ; EVEN PARITY REQUESTED?
  496.     JNE    P2        ; JUMP IF NOT
  497.     MOV    AL,1AH        ; SELECT EVEN PARITY
  498.     JMP    SHORT P3    ; CONTINUE
  499. P2:    CMP    PARITY[SI],'M'  ; MARK PARITY REQUESTED?
  500.     JNE    P3        ; JUMP IF NOT
  501.     MOV    AL,2AH        ; SELECT MARK PARITY
  502. P3:    TEST    STOP_BITS[SI],2 ; 2 STOP BITS REQUESTED?
  503.     JZ    STOP1        ; NO
  504.     OR    AL,4        ; YES
  505. STOP1:    MOV    DX,LCR[SI]    ; LINE CONTROL REGISTER
  506.     OUT    DX,AL        ; SET 8250 PARITY MODE AND DLAB=0
  507.  
  508. ; ENABLE INTERRUPTS ON 8259 AND 8250
  509.     IN    AL,INTA01    ; SET ENABLE BIT ON 8259
  510.     AND    AL,NIRQ[SI]
  511.     OUT    INTA01,AL
  512.     MOV    DX,IER[SI]    ; ENABLE INTERRUPTS ON 8250
  513.     MOV    AL,5        ; RECEIVE & LINE ERROR
  514.     OUT    DX,AL
  515.     JMP    $+2        ; I/O DELAY FOR JR
  516.     MOV    DX,MCR[SI]    ; SET DTR AND ENABLE INT DRIVER
  517.     MOV    AL,0BH
  518.     OUT    DX,AL
  519.  
  520. OCX:    STI            ; INTERRUPTS ON
  521.     pop si
  522.     mov sp,bp
  523.     pop bp
  524.     RET            ; DONE
  525. _open_com    ENDP
  526.     PAGE
  527. ;
  528. ; CLOSE_COM - TURNS OFF INTERRUPTS FROM THE COMMUNICATIONS PORT
  529. ;
  530. _close_com    PROC FAR
  531.     push bp
  532.     mov bp,sp
  533.     push si
  534.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  535.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  536.     JZ    CCX        ; ABORT IF NOT
  537.  
  538. ; TURN OFF 8250
  539.     MOV    DX,IER[SI]
  540.     MOV    AL,0
  541.     OUT    DX,AL
  542.  
  543. ; TURN OFF 8259
  544.     MOV    DX,INTA01
  545.     IN    AL,DX
  546.     OR    AL,IRQ[SI]
  547.     JMP    $+2        ; DELAY FOR AT
  548.     OUT    DX,AL
  549.  
  550. CCX:    pop si
  551.     mov sp,bp
  552.     pop bp
  553.     RET
  554. _close_com    ENDP
  555.     PAGE
  556. ;
  557. ; DTR_OFF - TURNS OFF DTR TO TELL MODEMS THAT THE TERMINAL HAS GONE AWAY
  558. ;        AND TO HANG UP THE PHONE
  559. ;
  560. _dtr_off    PROC FAR
  561.     push bp
  562.     mov bp,sp
  563.     push si
  564.     PUSHF            ; SAVE FLAGS
  565.     PUSH    AX        ; SAVE REGS
  566.     PUSH    DX
  567.     PUSH    SI
  568.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  569.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  570.     JZ    DFX        ; ABORT IF NOT
  571.  
  572.     MOV    DX,MCR[SI]
  573.     MOV    AL,08H        ; DTR OFF, RTS OFF, OUT2 ON
  574.     OUT    DX,AL
  575. DFX:    POP    SI        ; RECOVER REGS
  576.     POP    DX
  577.     POP    AX
  578.     POPF            ; RECOVER FLAGS
  579.     pop si
  580.     mov sp,bp
  581.     pop bp
  582.     RET
  583. _dtr_off    ENDP
  584. ;
  585. ; DTR_ON - TURNS DTR ON
  586. ;
  587. _dtr_on PROC FAR
  588.     push bp
  589.     mov bp,sp
  590.     push si
  591.     PUSHF            ; SAVE FLAGS
  592.     PUSH    AX        ; SAVE REGS
  593.     PUSH    DX
  594.     PUSH    SI
  595.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  596.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  597.     JZ    DNX        ; ABORT IF NOT
  598.  
  599.     MOV    DX,MCR[SI]
  600.     MOV    AL,0BH
  601.     OUT    DX,AL
  602. DNX:    POP    SI        ; RECOVER REGS
  603.     POP    DX
  604.     POP    AX
  605.     POPF            ; RECOVER FLAGS
  606.     pop si
  607.     mov sp,bp
  608.     pop bp
  609.     RET            ; DONE
  610. _dtr_on ENDP
  611.     PAGE
  612. ;
  613. ; R_COUNT - RETURNS NUMBER OF BYTES IN THE RECEIVE BUFFER IN AX
  614. ;          total in DX
  615. ;
  616. _r_count    PROC FAR
  617.     push bp
  618.     mov bp,sp
  619.     push si
  620.     PUSHF            ; SAVE FLAGS
  621.     PUSH    SI        ; SAVE SI
  622.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  623.     MOV    AX,0        ; NOTHING RECEIVED IF NOT INSTALLED
  624.     mov dx,R_SIZE
  625.  
  626.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  627.     JZ    RCX        ; ABORT IF NOT
  628.  
  629.     MOV    AX,SIZE_RDATA[SI] ; GET NUMBER OF BYTES USED
  630. RCX:    POP    SI        ; RESTORE SI
  631.     POPF            ; RESTORE FLAGS
  632.     pop si
  633.     mov sp,bp
  634.     pop bp
  635.     RET
  636. _r_count    ENDP
  637.     PAGE
  638. ;
  639. ; RECEIVE - RETURNS THE NEXT CHARACTER FROM THE RECEIVE BUFFER IN AL
  640. ;         AND REMOVES IT FROM THE BUFFER
  641. ;         THE PARITY BIT IS STRIPPED OFF
  642. ;
  643. _receive_com    PROC FAR
  644.     push bp
  645.     mov bp,sp
  646.     push si
  647.     PUSHF                ; SAVE FLAGS
  648.     PUSH    BX            ; SAVE REGS
  649.     PUSH    SI
  650.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  651.     mov    ax,-1 ; -1 if bad call
  652.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  653.     JZ    RCVX            ; ABORT IF NOT
  654.     CMP    SIZE_RDATA[SI],0    ; ANY CHARACTERS?
  655.     JE    RCVX            ; ABORT IF NOT
  656.  
  657. ; GOOD CALL
  658.     mov ah,0    ; good call
  659.     MOV    BX,START_RDATA[SI]    ; GET POINTER TO OLDEST CHAR
  660.     MOV    AL,RDATA[SI][BX]    ; GET CHAR FROM BUFFER
  661. ; MOD BY LBA, 10/6/85 FOR PROPER SUPPORT OF NO PARITY COMMUNICATIONS
  662.     CMP    PARITY[SI],'N'          ; ARE WE RUNNING WITH NO PARITY?
  663.     JE    L11            ; IF SO, DON'T STRIP HIGH BIT
  664. ; END OF MOD
  665.     AND    AL,7FH            ; STRIP PARITY BIT
  666. L11:    INC    BX            ; BUMP START_RDATA
  667.     CMP    BX,R_SIZE        ; SEE IF PAST END
  668.     JB    L12            ; IF NOT THEN SKIP
  669.     MOV    BX,0            ; ADJUST TO BEGINNING
  670. L12:    MOV    START_RDATA[SI],BX    ; SAVE THE NEW START_RDATA VALUE
  671.     DEC    SIZE_RDATA[SI]        ; ONE LESS CHARACTER
  672.     CMP    XON_XOFF[SI],'E'        ; FLOW CONTROL ENABLED?
  673.     JNE    RCVX            ; DO NOTHING IF DISABLED
  674.     CMP    HOST_OFF[SI],1        ; HOST TURNED OFF?
  675.     JNE    RCVX            ; JUMP IF NOT
  676.     CMP    SIZE_RDATA[SI],R_SIZE/20 ; RECEIVE BUFFER NEARLY EMPTY?
  677.     JGE    RCVX            ; DONE IF NOT
  678.     MOV    HOST_OFF[SI],0        ; TURN ON HOST IF SO
  679.     PUSH    AX            ; SAVE RECEIVED CHAR
  680.     MOV    AL,CONTROL_Q        ; TELL HIM TO TALK
  681.     CLI                ; TURN OFF INTERRUPTS
  682.     CALL    SENDII            ; SEND IMMEDIATELY INTERNAL
  683.     STI                ; INTERRUPTS BACK ON
  684.     POP    AX            ; RESTORE RECEIVED CHAR
  685. RCVX:    POP    SI            ; RECOVER REGS
  686.     POP    BX
  687.     POPF                ; RECOVER FLAGS
  688.     pop si
  689.     mov sp,bp
  690.     pop bp
  691.     RET                ; DONE
  692. _receive_com    ENDP
  693.     PAGE
  694. ;
  695. ; S_COUNT - RETURNS IN AX THE AMOUNT OF FREE SPACE
  696. ;           REMAINING IN THE TRANSMIT BUFFER
  697. ;     DX total size
  698. ;
  699. _s_count    PROC FAR
  700.     push bp
  701.     mov bp,sp
  702.     push si
  703.     PUSHF            ; SAVE FLAGS
  704.     PUSH    SI        ; SAVE SI
  705.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  706.     MOV    AX,0        ; NO SPACE LEFT IF NOT INSTALLED
  707.     mov dx,S_SIZE
  708.  
  709.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  710.     JZ    SCX        ; ABORT IF NOT
  711.  
  712.     MOV    AX,S_SIZE    ; GET THE SIZE OF THE X-MIT BUFFER
  713.     SUB    AX,SIZE_TDATA[SI] ; SUBTRACT THE NUMBER OF BYTES USED
  714. SCX:    POP    SI        ; RECOVER SI
  715.     POPF            ; RESTORE FLAGS
  716.     pop si
  717.     mov sp,bp
  718.     pop bp
  719.     RET
  720. _s_count    ENDP
  721.     PAGE
  722. ;
  723. ; SEND - SEND A CHARACTER
  724. ;    [bp+6] = char
  725. ;
  726. _send_com    PROC FAR
  727.     push bp
  728.     mov bp,sp
  729.     push si
  730.     mov al,[bp+6]
  731.     PUSHF                ; SAVE FLAGS
  732.     PUSH    AX            ; SAVE REGS
  733.     PUSH    BX
  734.     PUSH    DX
  735.     PUSH    SI
  736.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  737.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  738.     JZ    L44            ; ABORT IF NOT
  739.  
  740.     CMP    SIZE_TDATA[SI],S_SIZE    ; BUFFER FULL?
  741.     JL    L4A            ; JUMP IF NOT
  742.     INC    WORD PTR EOVFLOW[SI]    ; BUMP ERROR COUNT
  743.     JMP    SHORT L44        ; PUNT
  744. L4A:    MOV    BX,END_TDATA[SI]    ; BX POINTS TO FREE SPACE
  745.     MOV    TDATA[SI][BX],AL    ; MOVE CHAR TO BUFFER
  746.     INC    BX            ; INCREMENT END_TDATA
  747.     CMP    BX,S_SIZE        ; SEE IF PAST END
  748.     JL    L4            ; IF NOT THEN SKIP
  749.     MOV    BX,0            ; ADJUST TO BEGINNING
  750. L4:    MOV    END_TDATA[SI],BX    ; SAVE NEW END_TDATA
  751.     INC    SIZE_TDATA[SI]        ; ONE MORE CHARACTER IN X-MIT BUFFER
  752.     MOV    DX,IER[SI]        ; INTERRUPT ENABLE REGISTER
  753.     IN    AL,DX            ; GET IT
  754.     TEST    AL,2            ; SEE IF TX INTERRUPTS ARE ENABLED
  755.     JNZ    L44            ; JUMP IF SO
  756.     MOV    AL,7            ; IF NOT THEN RCV, TX, LINE ERROR
  757.     OUT    DX,AL            ; ARE ENABLED
  758. L44:    POP    SI            ; RESTORE REGS
  759.     POP    DX
  760.     POP    BX
  761.     POP    AX
  762.     POPF                ; RESTORE FLAGS
  763.     pop si
  764.     mov sp,bp
  765.     pop bp
  766.     RET                ; DONE
  767. _send_com    ENDP
  768.     PAGE
  769. ;
  770. ; SENDI - SEND A CHARACTER IMMEDIATELY
  771. ; [bp+6] = char to send
  772. ;
  773. _sendi_com    PROC FAR
  774.     push bp
  775.     mov bp,sp
  776.     push si
  777.     mov al,[bp+6]
  778.     PUSHF                ; SAVE FLAGS
  779.     PUSH    AX            ; SAVE REGS
  780.     PUSH    BX
  781.     PUSH    DX
  782.     PUSH    SI
  783.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  784.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  785.     JZ    LQ44            ; ABORT IF NOT
  786.  
  787.     CLI                ; MASK INTERRUPTS
  788.     CALL    SENDII            ; CALL INTERNAL SEND IMMEDIATE
  789.     STI                ; INTERRRUPTS BACK ON
  790.  
  791. LQ44:    POP    SI            ; RESTORE REGS
  792.     POP    DX
  793.     POP    BX
  794.     POP    AX
  795.     POPF                ; RESTORE FLAGS
  796.     pop si
  797.     mov sp,bp
  798.     pop bp
  799.     RET                ; DONE
  800. _sendi_com    ENDP
  801.     PAGE
  802. ;
  803. ; INTERNAL ROUTINE
  804. ; DEPENDS ON CALLER TO KEEP INTERRUPTS CLEARED AND SET SI
  805. ; SENDI - SEND A CHARACTER IMMEDIATELY (PUT AT BEGINNING OF QUEUE)
  806. ; AL = CHAR TO WRITE
  807. ;
  808. SENDII    PROC    NEAR
  809.     PUSH    DX            ; SAVE DX
  810.     CMP    SIZE_TDATA[SI],S_SIZE    ; BUFFER FULL?
  811.     JB    LI4A            ; JUMP IF NOT
  812.     INC    WORD PTR EOVFLOW[SI]    ; BUMP ERROR COUNT
  813.     MOV    BX,START_TDATA[SI]    ; BX POINTS TO FIRST CHAR IN BUFFER
  814.     MOV    TDATA[SI][BX],AL    ; CLOBBER FIRST CHAR IN BUFFER
  815.     JMP    SHORT LI4B        ; CONTINUE
  816. LI4A:    MOV    BX,START_TDATA[SI]    ; BX POINTS TO FIRST CHAR IN BUFFER
  817.     DEC    BX            ; BACKUP THE PTR
  818.     CMP    BX,-1            ; BEFORE BEGINNING?
  819.     JNE    LI4            ; JUMP IF NOT
  820.     MOV    BX,S_SIZE-1        ; POINT TO END IF SO
  821. LI4:    MOV    TDATA[SI][BX],AL    ; MOVE CHAR TO BUFFER
  822.     MOV    START_TDATA[SI],BX    ; SAVE NEW START_TDATA
  823.     INC    SIZE_TDATA[SI]        ; ONE MORE CHARACTER IN X-MIT BUFFER
  824. LI4B:    MOV    DX,IER[SI]        ; INTERRUPT ENABLE REGISTER
  825.     IN    AL,DX            ; GET IT
  826.     TEST    AL,2            ; SEE IF TX INTERRUPTS ARE ENABLED
  827.     JNZ    LI44            ; JUMP IF SO
  828.     MOV    AL,7            ; IF NOT THEN RCV, TX, LINE ERROR
  829.     OUT    DX,AL            ; ARE ENABLED
  830. LI44:    POP    DX            ; RECOVER DX
  831.     RET                ; DONE
  832. SENDII    ENDP
  833.     PAGE
  834. ;
  835. ; S_LOCAL
  836. ;
  837. _send_local    PROC FAR
  838.     push bp
  839.     mov bp,sp
  840.     push si
  841.     mov al,[bp+6]
  842.     PUSHF                ; SAVE FLAGS
  843.     PUSH    AX            ; SAVE REGS
  844.     PUSH    BX
  845.     PUSH    SI
  846.     MOV    SI,CURRENT_AREA     ; SI POINTS TO DATA AREA
  847.     TEST    INSTALLED[SI],1     ; PORT INSTALLED?
  848.     JZ    SLX            ; ABORT IF NOT
  849.  
  850.     CLI                ; INTERRUPTS OFF
  851.     CMP    SIZE_RDATA[SI],R_SIZE    ; SEE IF ANY ROOM
  852.     JB    L13A            ; SKIP IF ROOM
  853.     INC    WORD PTR EOVFLOW[SI]    ; BUMP OVERFLOW COUNT
  854.     JMP    SHORT L14        ; PUNT
  855. L13A:    MOV    BX,END_RDATA[SI]    ; BX POINTS TO FREE SPACE
  856.     MOV    RDATA[SI][BX],AL    ; SEND DATA TO BUFFER
  857.     INC    BX            ; INCREMENT END_RDATA POINTER
  858.     CMP    BX,R_SIZE        ; SEE IF GONE PAST END
  859.     JL    L13            ; IF NOT THEN SKIP
  860.     MOV    BX,0            ; ELSE ADJUST TO BEGINNING
  861. L13:    MOV    END_RDATA[SI],BX    ; SAVE VALUE
  862.     INC    SIZE_RDATA[SI]        ; GOT ONE MORE CHARACTER
  863. L14:    STI                ; INTERRUPTS BACK ON
  864.  
  865. SLX:    POP    SI            ; RECOVER REGS
  866.     POP    BX
  867.     POP    AX
  868.     POPF                ; RECOVER FLAGS
  869.     pop si
  870.     mov sp,bp
  871.     pop bp
  872.     RET                ; DONE
  873. _send_local    ENDP
  874.     PAGE
  875. ;
  876. ; BREAK - CAUSES A BREAK TO BE SENT OUT ON THE LINE
  877. ;
  878. _break_com    PROC FAR
  879.     push bp
  880.     mov bp,sp
  881.     push si
  882.     PUSHF            ; SAVE FLAGS
  883.     PUSH    AX        ; SAVE REGS
  884.     PUSH    CX
  885.     PUSH    DX
  886.     MOV    SI,CURRENT_AREA ; SI POINTS TO DATA AREA
  887.     TEST    INSTALLED[SI],1 ; PORT INSTALLED?
  888.     JZ    BRX        ; ABORT IF NOT
  889.  
  890.     MOV    DX,LCR[SI]    ; LINE CONTROL REGISTER
  891.     IN    AL,DX        ; GET CURRENT SETTING
  892.     JMP    $+2        ; I/O DELAY FOR JR
  893.     OR    AL,40H        ; TURN ON BREAK BIT
  894.     OUT    DX,AL        ; SET IT ON THE 8250
  895.     MOV    CX,0C000H    ; WAIT APPROX. 1/4 SEC.
  896. BREAK1: LOOP    BREAK1        ; BUSY WAIT
  897.     AND    AL,0BFH     ; TURN OFF BREAK BIT
  898.     OUT    DX,AL        ; RESTORE LINE CONTROL REGISTER
  899. BRX:    POP    DX        ; RECOVER REGS
  900.     POP    CX
  901.     POP    AX
  902.     POPF            ; RECOVER FLAGS
  903.     pop si
  904.     mov sp,bp
  905.     pop bp
  906.     RET            ; DONE
  907. _break_com    ENDP
  908.     PAGE
  909. ;
  910. ; COM_ERRORS - RETURN POINTER IN dx:ax TO ERROR COUNTS
  911. ;
  912. _com_errors    PROC FAR
  913.     push bp
  914.     mov bp,sp
  915.     mov ax,OFFSET DGROUP:CURRENT_AREA
  916.     add ax,ERROR_BLOCK
  917.     mov dx,ds
  918.     mov sp,bp
  919.     pop bp
  920.     RET            ; DONE
  921. _com_errors    ENDP
  922.     PAGE
  923. ;
  924. ; INTERNAL ROUTINE
  925. ; BUMP ERROR COUNTS FROM LINE STATUS IN AL
  926. ;
  927. E_BUMP    PROC    NEAR
  928.     TEST    AL,2        ; OVERRUN ERROR?
  929.     JZ    LSI1        ; JUMP IF NOT
  930.     INC    WORD PTR EOVRUN[SI]    ; ELSE BUMP ERROR COUNT
  931. LSI1:    TEST    AL,4        ; PARITY ERROR?
  932.     JZ    LSI2        ; JUMP IF NOT
  933.     INC    WORD PTR EPARITY[SI]    ; ELSE BUMP ERROR COUNT
  934. LSI2:    TEST    AL,8        ; FRAMING ERROR?
  935.     JZ    LSI3        ; JUMP IF NOT
  936.     INC    WORD PTR EFRAME[SI]    ; ELSE BUMP ERROR COUNT
  937. LSI3:    TEST    AL,16        ; BREAK RECEIVED?
  938.     JZ    LSI4        ; JUMP IF NOT
  939.     INC    WORD PTR EBREAK[SI]    ; ELSE BUMP ERROR COUNT
  940. LSI4:    RET            ; DONE
  941. E_BUMP    ENDP
  942.     PAGE
  943. ;
  944. ; INTERNAL ROUTINE
  945. ; MODEM SEND PROTOCOL
  946. ;
  947. M_PROTOCOL PROC NEAR
  948.     CMP    CONNECTION[SI],'M' ; MODEM CONNECTION?
  949.     JNE    S3        ; IF NOT, SKIP DSR & CTS PROTOCOL
  950.  
  951. ; TELL MODEM WE'RE READY TO SEND
  952.     MOV    DX,MCR[SI]    ; MODEM CONTROL REGISTER
  953.     MOV    AL,00001011B    ; OUT 2, RTS, DTR
  954.     OUT    DX,AL        ; TERMINAL READY, REQUEST TO SEND
  955.     JMP    $+2        ; I/O DELAY FOR JR
  956.  
  957. ; WAIT UNTIL MODEM SAYS DATA SET READY
  958.     MOV    CX,1000     ; TIMEOUT COUNT
  959.     MOV    DX,MSR[SI]    ; MODEM STATUS REGISTER
  960. S1:    IN    AL,DX        ; GET MODEM STATUS
  961.     TEST    AL,20H        ; DATA SET READY?
  962.     JNZ    S1X        ; YES, TEST CLEAR TO SEND
  963.     LOOP    S1        ; NO, BUSY WAIT
  964.     INC    WORD PTR EDSR[SI]    ; BUMP ERROR COUNT
  965.     JMP    SHORT S3    ; WE TIMED OUT
  966. S1X:
  967. ; WAIT UNTIL MODEM SAYS IT'S CLEAR TO SEND
  968.     MOV    CX,1000     ; TIMEOUT COUNT
  969. S2:    IN    AL,DX        ; GET MODEM STATUS
  970.     TEST    AL,10H        ; CLEAR TO SEND?
  971.     JNZ    S2X        ; YES
  972.     LOOP    S2        ; NO, KEEP TRYING
  973.     INC    WORD PTR ECTS[SI]    ; BUMP ERROR COUNT - WE TIMED OUT
  974. S2X:
  975. ; TEST FOR TRANSMITTER READY
  976. S3:    MOV    DX,LSR[SI]    ; LINE STATUS REGISTER
  977.     IN    AL,DX        ; GET LINE STATUS
  978.     TEST    AL,20H        ; TRANSMITTER READY?
  979.     JNZ    S4        ; SKIP IF SO
  980.     INC    WORD PTR EXMIT[SI]    ; ELSE BUMP ERROR COUNT
  981. S4:    RET            ; DONE
  982. M_PROTOCOL ENDP
  983.     PAGE
  984. ;
  985. ; INTERNAL ROUTINES FOR FLOW CONTROL
  986. ;
  987. ; FLOW_IN - RESPOND TO FLOW CONTROL COMMANDS FROM HOST
  988. ; FLOW_OUT - ISSUE FLOW CONTROL COMMANDS TO HOST
  989. ;
  990. FLOW_IN PROC    NEAR
  991.     PUSH    AX        ; SAVE CHAR
  992.     CMP    XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
  993.     JNE    FI_NOCARRY    ; DO NOTHING IF DISABLED
  994.     AND    AL,7FH        ; STRIP PARITY
  995.     CMP    AL,CONTROL_S    ; STOP COMMAND RECEIVED?
  996.     JNE    FI_1        ; JUMP IF NOT
  997.     MOV    PC_OFF[SI],1    ; WE MUST SHUT UP
  998.     STC            ; Flag we got special character
  999.     JMP    SHORT FI_EXIT    ; Continue
  1000.  
  1001. FI_1:    CMP    AL,CONTROL_Q    ; GO COMMAND RECEIVED?
  1002.     JNE    FI_NOCARRY    ; NO, MUST BE NORMAL CHAR
  1003.     MOV    PC_OFF[SI],0    ; WE START TALKING AGAIN
  1004.     STC            ; Flag we got special character
  1005.     JMP    SHORT FI_EXIT    ; Continue
  1006.  
  1007. FI_NOCARRY:
  1008.     CLC            ; Not special character, no carry
  1009. FI_EXIT:
  1010.     POP    AX        ; RESTORE CHAR
  1011.     RET            ; DONE
  1012. FLOW_IN ENDP
  1013. ;
  1014. FLOW_OUT PROC    NEAR
  1015.     CMP    XON_XOFF[SI],'E'; FLOW CONTROL ENABLED?
  1016.     JNE    FO_X        ; DO NOTHING IF DISABLED
  1017.     CMP    HOST_OFF[SI],1    ; HOST TURNED OFF?
  1018.     JE    FO_X        ; JUMP IF SO
  1019.     CMP    SIZE_RDATA[SI],R_SIZE/2 ; RECEIVE BUFFER NEARLY FULL?
  1020.     JLE    FO_X        ; DONE IF NOT
  1021.     MOV    AL,CONTROL_S    ; TURN OFF HOST IF SO
  1022.     CALL    SENDII        ; SEND IMMEDIATELY INTERNAL
  1023.     MOV    HOST_OFF[SI],1    ; HOST IS NOW OFF
  1024. FO_X:    RET            ; DONE
  1025. FLOW_OUT ENDP
  1026.     PAGE ;
  1027. ;
  1028. ; _MODEM_STATUS - Returns the modem status register in AL
  1029. ;
  1030. ; Bits are:    0x80:    -CD    (Carrier Detect, inverted)
  1031. ;        0x40:    -RI    (Ring Indicator, inverted)
  1032. ;        0x20:    -DSR    (Data Set Ready, inverted)
  1033. ;        0x10:    -CTS    (Clear to Send, inverted)
  1034. ;        0x08:    Delta Carrier Detect    (CD changed)
  1035. ;        0x04:    Trailing edge of RI    (RI went OFF)
  1036. ;        0x02:    Delta DSR        (DSR changed)
  1037. ;        0x01:    Delta CTS        (CTS changed)
  1038. ;
  1039. _modem_status    PROC FAR
  1040.     push bp
  1041.     mov bp,sp
  1042.     PUSH DX
  1043.     PUSH SI
  1044.     MOV SI,CURRENT_AREA        ; Point to block for selected port
  1045.     MOV DX,MSR[SI]            ; IO Addr of Modem Status Register
  1046.     IN AL,DX            ; Get the live value
  1047.     XOR AH,AH            ; Flush unwanted bits
  1048.     POP SI
  1049.     POP DX
  1050.     mov sp,bp
  1051.     pop bp
  1052.     RET
  1053. _modem_status    ENDP
  1054.     PAGE
  1055. ;
  1056. ; INT_HNDLR1 - HANDLES INTERRUPTS GENERATED BY COM1:
  1057. ;
  1058. INT_HNDLR1 PROC  FAR
  1059.     PUSH    SI        ; SAVE SI
  1060.     MOV    SI,OFFSET DGROUP:AREA1    ; DATA AREA FOR COM1:
  1061.     JMP    SHORT INT_COMMON ; CONTINUE
  1062. ;
  1063. ; INT_HNDLR2 - HANDLES INTERRUPTS GENERATED BY COM2:
  1064. ;
  1065. INT_HNDLR2 PROC  FAR
  1066.     PUSH    SI        ; SAVE SI
  1067.     MOV    SI,OFFSET DGROUP:AREA2    ; DATA AREA FOR COM2:
  1068.     JMP    SHORT INT_COMMON ; CONTINUE
  1069. ;
  1070. ; INT_HNDLR3 - HANDLES INTERRUPTS GENERATED BY COM3:
  1071. ;
  1072. INT_HNDLR3 PROC  FAR
  1073.     PUSH    SI        ; SAVE SI
  1074.     MOV    SI,OFFSET DGROUP:AREA3    ; DATA AREA FOR COM3:
  1075.     JMP    SHORT INT_COMMON ; CONTINUE
  1076. ;
  1077. ; INT_HNDLR4 - HANDLES INTERRUPTS GENERATED BY COM4:
  1078. ;
  1079. INT_HNDLR4 PROC  FAR
  1080.     PUSH    SI        ; SAVE SI
  1081.     MOV    SI,OFFSET DGROUP:AREA4    ; DATA AREA FOR COM4:
  1082.     ; Fall into INT_COMMON
  1083.  
  1084. ;
  1085. ; BODY OF INTERRUPT HANDLER
  1086. ;
  1087. INT_COMMON:
  1088.     PUSH    AX        ; SAVE REGS
  1089.     PUSH    BX
  1090.     PUSH    CX
  1091.     PUSH    DX
  1092.     PUSH    BP
  1093.     PUSH    DI
  1094.     PUSH    DS
  1095.     PUSH    ES
  1096.  
  1097.     MOV AX,DGROUP        ; Offsets are relative to DGROUP [WWP]
  1098.     MOV    DS,AX        ; TO DS
  1099.  
  1100. ; CLEAR THE INTERRUPT CONTROLLER FLAG
  1101.     MOV    DX,INTA00    ; 8259 CONTROL PORT
  1102.     MOV    AL,EOI[SI]    ; SPECIFIC END OF INTERRUPT
  1103.     OUT    DX,AL        ; CLEAR FLAG
  1104.  
  1105. ; FIND OUT WHERE INTERRUPT CAME FROM AND JUMP TO ROUTINE TO HANDLE IT
  1106. REPOLL:
  1107.     MOV    DX,IIR[SI]    ; READ INTERRUPT STATUS REGISTER
  1108.     IN    AL,DX
  1109.     CMP    AL,4
  1110.     JE    RX_INT        ; IF FROM THE RECEIVER
  1111.     CMP    AL,2
  1112.     JE    TX_INT        ; IF FROM THE TRANSMITTER
  1113.     CMP    AL,6
  1114.     JE    LSTAT_INT    ; INTERRUPT BECAUSE OF LINE STATUS
  1115.     CMP    AL,0
  1116.     JE    MSTAT_INT    ; INTERRUPT BECAUSE OF MODEM STATUS
  1117.     JMP    FAR PTR INT_END ; DONE, EXIT (DON'T FIX FAR PTR STUFF)
  1118.  
  1119. LSTAT_INT:
  1120.     MOV    DX,LSR[SI]    ; READ AND IGNORE LINE STATUS
  1121.     IN    AL,DX        ;
  1122.     CALL    E_BUMP        ; JUST BUMP ERROR COUNTS
  1123.     JMP    REPOLL        ; SEE IF ANY MORE INTERRUPTS
  1124.  
  1125. MSTAT_INT:
  1126.     MOV    DX,MSR[SI]    ; READ AND IGNORE MODEM STATUS
  1127.     IN    AL,DX        ;
  1128.     JMP    REPOLL        ; SEE IF ANY MORE INTERRUPTS
  1129.  
  1130. TX_INT:
  1131.     CMP    PC_OFF[SI],1    ; HAVE WE BEEN TOLD TO SHUT UP?
  1132.     JNE    GOODTX1     ; JUMP IF NOT
  1133.     CMP    HOST_OFF[SI],1    ; HAS HOST ALSO SHUT UP?
  1134.     JNE    SEND_NO_MORE    ; JUMP IF NOT
  1135.  
  1136. ; CLEAR XON/XOFF DEADLOCK
  1137.     MOV    PC_OFF[SI],0    ; WE SPEAK
  1138.     MOV    HOST_OFF[SI],0    ; THEY REPLY
  1139.     MOV    AL,CONTROL_Q    ; BUT ONLY WHEN
  1140.     CALL    SENDII        ; WE LET THEM
  1141.  
  1142. GOODTX1:
  1143.     CMP    SIZE_TDATA[SI],0 ; SEE IF ANY MORE DATA TO SEND
  1144.     JG    HAVE_DATA    ; IF POSITIVE THEN THERE IS DATA TO SEND
  1145.  
  1146. ; IF NO DATA TO SEND THEN RESET TX INTERRUPT AND RETURN
  1147. SEND_NO_MORE:
  1148.     MOV    DX,IER[SI]        ;
  1149.     MOV    AL,5            ; JUST RCV AND LINE ERROR
  1150.     OUT    DX,AL            ; ARE SET
  1151.     JMP    REPOLL            ;
  1152.  
  1153. HAVE_DATA:
  1154.     CALL    M_PROTOCOL        ; DO MODEM PROTOCOL IF NECESSARY
  1155.  
  1156.     MOV    BX,START_TDATA[SI]    ; BX POINTS TO NEXT CHAR. TO BE SENT
  1157.     MOV    AL,TDATA[SI][BX]    ; GET DATA FROM BUFFER
  1158.     MOV    DX,DATREG[SI]        ; DX EQUALS PORT TO SEND DATA TO
  1159.     OUT    DX,AL            ; SEND DATA
  1160.     INC    BX            ; INCREMENT START_TDATA
  1161.     CMP    BX,S_SIZE        ; SEE IF GONE PAST END
  1162.     JB    NTADJ            ; IF NOT THEN SKIP
  1163.     MOV    BX,0            ; RESET TO BEGINNING
  1164. NTADJ:    MOV    START_TDATA[SI],BX    ; SAVE START_TDATA
  1165.     DEC    SIZE_TDATA[SI]        ; ONE LESS CHARACTER IN X-MIT BUFFER
  1166.     JMP    REPOLL
  1167.  
  1168. RX_INT:
  1169.     MOV    DX,DATREG[SI]        ; 8250 DATA REGISTER
  1170.     IN    AL,DX            ; GET DATA
  1171.     CALL    FLOW_IN         ; RESPOND TO F.C. COMMANDS FROM HOST
  1172.     JC    REPOLL            ; If flow control, do not save
  1173.                     ; ahd
  1174.     CMP    SIZE_RDATA[SI],R_SIZE    ; SEE IF ANY ROOM
  1175.     JL    GOOD_RX1        ; CONTINUE IF SO
  1176.     INC    WORD PTR EOVFLOW[SI]    ; BUMP OVERFLOW ERROR COUNT
  1177.     JMP    REPOLL            ; PUNT
  1178. GOOD_RX1:
  1179.     MOV    BX,END_RDATA[SI]    ; BX POINTS TO FREE SPACE
  1180.     MOV    RDATA[SI][BX],AL    ; MOVE DATA TO BUFFER
  1181.     INC    SIZE_RDATA[SI]        ; GOT ONE MORE CHARACTER
  1182.     INC    BX            ; INCREMENT END_RDATA POINTER
  1183.     CMP    BX,R_SIZE        ; SEE IF GONE PAST END
  1184.     JB    NRADJ            ; IF NOT THEN SKIP
  1185.     MOV    BX,0            ; ELSE ADJUST TO BEGINNING
  1186. NRADJ:    MOV    END_RDATA[SI],BX    ; SAVE VALUE
  1187. DO_FLOW:                ; ahd
  1188.     CALL    FLOW_OUT        ; ISSUE FLOW CONTROL COMMANDS TO HOST
  1189.     JMP    REPOLL            ;
  1190.  
  1191. INT_END:
  1192.     POP    ES        ; RESTORE REGS
  1193.     POP    DS
  1194.     POP    DI
  1195.     POP    BP
  1196.     POP    DX
  1197.     POP    CX
  1198.     POP    BX
  1199.     POP    AX
  1200.  
  1201.     POP    SI        ; RESTORE SI, TOO
  1202.     IRET
  1203. INT_HNDLR4 ENDP
  1204. INT_HNDLR3 ENDP
  1205. INT_HNDLR2 ENDP
  1206. INT_HNDLR1 ENDP
  1207. COM_TEXT    ENDS
  1208.     END
  1209.